﻿using Abp.Domain.Repositories;
using Abp.Web.Models;
using BRMC.IntelligentCommunity.IntelligentCommunity.Parkings;
using BRMC.IntelligentCommunity.IntelligentCommunity.Users;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using BRMC.IntelligentCommunity.Parkings;
using BRMC.IntelligentCommunity.Parkings.CarLog;

namespace BRMC.IntelligentCommunity.Web.Controllers
{

    public class VehicleManagementController : IntelligentCommunityAppServiceBase
    {
        private readonly IRepository<CarInfo, long> _carInfoRepository;

        private readonly IRepository<Parking, long> _parkingRepository;
        private readonly IRepository<Place, long> _place;
        private readonly IRepository<User_base_info, long> _user_base_info;
        private readonly IRepository<CarlogRealTime, long> _carlogRealTime;
        private readonly IRepository<Device, long> _device;
        private readonly IRepository<CarLogHistory, long> _carLogHistory;
        private readonly IRepository<UserCarInfo, long> _userCarInfo;
        private readonly IRepository<UserParkinginfo, long> _userParkinginfo;
        private readonly IRepository<ParkingsBillingScheme, long> _parkingsBillingScheme;     //Device
        private readonly IRepository<ParkGuard, long> _parkGuard;
        protected IHttpContextAccessor httpContext;
        private readonly IParkingsBillingSchemeAppService _iParkingsBillingSchemeAppService;
        private readonly ICarLogHistoryAppService _iCarLogHistoryAppService;



        public VehicleManagementController(IRepository<CarInfo, long> carInfoRepository,
            IRepository<Parking, long> parkingRepository,
            IRepository<User_base_info, long> user_base_info,
             IRepository<ParkGuard, long> parkGuard,
             IRepository<Place, long> place,
             IRepository<CarlogRealTime, long> carlogRealTime,
             IRepository<CarLogHistory, long> carLogHistory,
              IRepository<UserCarInfo, long> userCarInfo,
              IRepository<UserParkinginfo, long> userParkinginfo,
              IRepository<ParkingsBillingScheme, long> parkingsBillingScheme,
              IRepository<Device, long> device,
             IHttpContextAccessor httpContextAccessor,
             IParkingsBillingSchemeAppService iParkingsBillingSchemeAppService,
             ICarLogHistoryAppService iCarLogHistoryAppService
            )
        {
            _carInfoRepository = carInfoRepository;
            _parkingRepository = parkingRepository;
            _user_base_info = user_base_info;
            httpContext = httpContextAccessor;
            _place = place;
            _carlogRealTime = carlogRealTime;
            _carLogHistory = carLogHistory;
            _userCarInfo = userCarInfo;
            _userParkinginfo = userParkinginfo;
            _parkingsBillingScheme = parkingsBillingScheme;
            _parkGuard = parkGuard;
            _device = device;
            _iParkingsBillingSchemeAppService = iParkingsBillingSchemeAppService;
            _iCarLogHistoryAppService = iCarLogHistoryAppService;
        }

        [HttpPost]
        [Route("licensePlateRecognition")]
        [DontWrapResult]
        public async Task<object> LicensePlateRecognition(string type, int mode, string plate_num, string plate_color, bool plate_val, int confidence, string car_logo, string car_sublogo, string car_color, string vehicle_type, long start_time, string park_id, string cam_id, string cam_ip, string vdc_type, bool is_whitelist, string triger_type, string picture, string closeup_pic)
        {
            var car = await _carInfoRepository.FirstOrDefaultAsync(c => c.LicenseColor == plate_color && c.CarNum == plate_num); //当前车辆信息

            DateTime dt = new DateTime(1970, 1, 1).AddSeconds(start_time);  //刷卡时间
            dt = dt.AddSeconds(8 * 60 * 60);
            var billingScheme = await _parkingsBillingScheme.FirstOrDefaultAsync(c => c.ParkingId == Convert.ToInt64(park_id));  //对应车场的计费规则

            var device = await _device.FirstOrDefaultAsync(c => c.Ipaddr == cam_ip && c.ParkingId == Convert.ToInt64(park_id));  //对应设备信息

            car = car == null ? await _carInfoRepository.InsertAsync( new CarInfo() { CarNum = plate_num, LicenseColor = plate_color, ParkingId = device.ParkingId, ParkingCode = device.ParkingCode, ParkingName = device.ParkingName, CarStatus = 0, CarType = 0, VehicleBrand = "未知", Neighbourhood_id = device.Neighbourhood_id, Neighbourhood_name = device.Neighbourhood_name ,TenantId=device.TenantId}) : car;

         //   object json = await CarIn(cam_id, cam_ip, vdc_type, car, dt, device);  // 进场

            var rjson = new object();
            if (vdc_type == "in")
            {
                //rjson = await CarIn(cam_id, cam_ip, vdc_type, car, dt, device);  // 进场

                await _iCarLogHistoryAppService.CarIn(car.Id, car.CarNum, device.ParkingId, dt, cam_id, cam_ip, device);
            }
            else
            {
                //rjson = await CarOut(cam_id, cam_ip, vdc_type, car, dt, device, billingScheme); //离场

                var costAndRemark = await _iCarLogHistoryAppService.CarOut(car.Id, car.CarNum, device.ParkingId, dt, cam_id, cam_ip, device);
            }

            rjson = ReturnJson(car);
            
            return rjson;
        }
        public static byte[] StringToHexByte(string str)
        {
            return StringToHexByte(str, false);
        }
        public static byte[] StringToHexByte(string str, bool isFilterChinese)
        {
            string hex = isFilterChinese ? FilterChinese(str) : ConvertChinese(str);

            //清除所有空格
            hex = hex.Replace(" ", "");
            //若字符个数为奇数，补一个0
            hex += hex.Length % 2 != 0 ? "0" : "";

            byte[] result = new byte[hex.Length / 2];
            for (int i = 0, c = result.Length; i < c; i++)
            {
                result[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
            }
            return result;
        }
        private static string ConvertChinese(string str)
        {
            StringBuilder s = new StringBuilder();
            foreach (short c in str.ToCharArray())
            {
                if (c <= 0 || c >= 127)
                {
                    s.Append(c.ToString("X4"));
                }
                else
                {
                    s.Append((char)c);
                }
            }
            return s.ToString();
        }

        private static string FilterChinese(string str)
        {
            StringBuilder s = new StringBuilder();
            foreach (short c in str.ToCharArray())
            {
                if (c > 0 && c < 127)
                {
                    s.Append((char)c);
                }
            }
            return s.ToString();
        }
        private async Task<object> CarIn(string cam_id, string cam_ip, string vdc_type, CarInfo car, DateTime dt, Device device)
        {
            //Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            //var encoding = Encoding.GetEncoding("GB2312");
            //byte[] bytes = encoding.GetBytes("0064FFFF621B000000000500000301FF000000000000000800BCBD46355A4B3237");

            //byte[] aa = { 0x00, 0x64,FF, };

            //byte[] bytesA = encoding.GetBytes(data);

            var userParking = await _userParkinginfo.FirstOrDefaultAsync(c => c.CarId == car.Id);

            var place = new Place();

            if (userParking != null)  //存在车位信息
            {
                place = await _place.FirstOrDefaultAsync(c => c.Id == userParking.PlaceId); //当前车辆关联的车位信息

                bool IsValid = dt < place.EndTime; //是否在有效期内
                bool IsUse = place.PlaceSatus == 1; //判断车位使用占用


                var carType = 0;

                if (IsValid) //是否超出期限
                {
                    carType = IsUse == true ? 3 : 2;
                }
                else
                {
                    carType = 3;
                }

                var carlog = new CarLogHistory()
                {
                    LogType = vdc_type == "in" ? 1 : 2,
                    ParkingId = place.ParkingId,
                    CamId = cam_id,
                    GuardId = device.GuardId,
                    Ipaddr = cam_ip,
                    CarType = car.CarType == 0 ? 2 : 1,
                    LogTime = dt,
                    TenantId = place.TenantId,
                    CarNum = car.CarNum,
                    Neighbourhood_id = place.Neighbourhood_id
                };

                await _carLogHistory.InsertAsync(carlog);  //插入进入场日志

                var carlogRealTime = new CarlogRealTime()
                {
                    ParkingId = place.ParkingId,
                    GuardId = device.GuardId,
                    CarNum = car.CarNum,
                    PlaceId = place.Id,
                    CarType = carType,
                    PayStatus = 1,
                    LogTime = dt,
                    TenantId = place.TenantId,
                    Neighbourhood_id = place.Neighbourhood_id

                };
                await _carlogRealTime.InsertAsync(carlogRealTime);

                place.PlaceSatus = 1;
                _place.Update(place);
            }
            else
            {


                var carlog = new CarLogHistory()
                {
                    LogType = vdc_type == "in" ? 1 : 2,
                    ParkingId = device.ParkingId,
                    CamId = cam_id,
                    GuardId = device.GuardId,
                    Ipaddr = cam_ip,
                    CarType = 0,
                    LogTime = dt,
                    TenantId = device.TenantId,
                    CarNum = car.CarNum,
                    Neighbourhood_id = device.Neighbourhood_id
                };

                await _carLogHistory.InsertAsync(carlog);  //插入进入场日志

                var carlogRealTime = new CarlogRealTime()
                {
                    ParkingId = device.ParkingId,
                    GuardId = device.GuardId,
                    CarNum = car.CarNum,
                    PlaceId = place.Id,
                    CarType = 0,
                    PayStatus = 2,
                    LogTime = dt,
                    TenantId = device.TenantId,
                    Neighbourhood_id = device.Neighbourhood_id

                };
                await _carlogRealTime.InsertAsync(carlogRealTime);
                //await _carInfoRepository.InsertAsync(car);
            }            
            var json = ReturnJson(car);
            return json;
        }

        private static string GetHexInfo(string str,int type)
        {
            var s = GethexString(str);
            var data = "";
            switch (type)
            {
                case 1:
                    var l = str.Length + 20;
                    var strA = l.ToString("x2");
                    var strB = ((str.Length) + 1).ToString("x2");
                    data = "0064FFFF62" + strA + "000000000500000301FF00000000000000" + strB + "00" + s;
                    break;
                case 2:
                     l = str.Length + 22;
                     strA = l.ToString("x2");
                     strB = ((str.Length) + 3).ToString("x2");
                    data = "0064FFFF62" + strA + "010000000500000301FF00000000000000" + strB + "00" + s;
                    break;
                case 3:
                     l = str.Length + 9;
                     strA = l.ToString("x2");
                     //strB = ((str.Length) + 8).ToString("x2");
                    data = "0064FFFF30" + strA + "01" + s;
                    break;
                default:
                    break;
            }
            
            var i = StringToHexByte(data);


            var m = GetCRCDatas(i);
            var hexString = BitConverter.ToString(m);
            hexString = hexString.Replace("-", "");
            return hexString;
        }

        private async Task<object> CarOut(string cam_id, string cam_ip, string vdc_type, CarInfo car, DateTime dt, Device device, ParkingsBillingScheme billingScheme)
        {
            var userParking = await _userParkinginfo.FirstOrDefaultAsync(c => c.CarId == car.Id);

            var place = new Place();
            var carType = 0;
            if (userParking != null)  //存在车位信息
            {
                place = await _place.FirstOrDefaultAsync(c => c.Id == userParking.PlaceId); //当前车辆关联的车位信息

                bool IsValid = dt < place.EndTime; //是否在有效期内
                bool IsUse = place.PlaceSatus == 1; //判断车位使用占用


           

                if (IsValid)  //在有效期内
                {
                    carType = IsUse == true ? 3 : 2;

                    var carlog = new CarLogHistory()
                    {
                        LogType = vdc_type == "in" ? 1 : 2,
                        ParkingId = place.ParkingId,
                        CamId = cam_id,
                        GuardId = device.GuardId,
                        Ipaddr = cam_ip,
                        CarType = car.CarType == 0 ? 2 : 1,
                        LogTime = dt,
                        TenantId = place.TenantId,
                        CarNum =car.CarNum,
                        Neighbourhood_id = place.Neighbourhood_id
                    };

                    await _carLogHistory.InsertAsync(carlog);  //插入进入场日志





                    var carlogRealTime = await _carlogRealTime.FirstOrDefaultAsync(c => c.CarNum == car.CarNum&&c.ParkingId==device.ParkingId);

                    await _carlogRealTime.DeleteAsync(carlogRealTime.Id);
                    place.PlaceSatus = 0;
                    _place.Update(place);
                }
                else    //超出有效期
                {
                    var outTiem = DateTimeToStamp(dt);


                    var carlogRealTime = await _carlogRealTime.FirstOrDefaultAsync(c => c.CarNum == car.CarNum && c.ParkingId == device.ParkingId);

                    var inTime = DateTimeToStamp(carlogRealTime.LogTime);
                   
                    var staytime = (outTiem - inTime) / 60;


                    var cost = billingScheme.CappedPrice == 0 ? ((staytime - billingScheme.FreeTime) / billingScheme.IntervalTime) * billingScheme.Univalent : billingScheme.CappedPrice; //如果设置了封顶价格,价格为封顶价格,否则为实际价格


                    carType = 3;
                    var carlog = new CarLogHistory()
                    {
                        LogType = vdc_type == "in" ? 1 : 2,
                        ParkingId = place.ParkingId,
                        CamId = cam_id,
                        GuardId = device.GuardId,
                        Ipaddr = cam_ip,
                        CarType = car.CarType == 0 ? 2 : 1,
                        LogTime = dt,
                        TenantId = place.TenantId,
                        Neighbourhood_id = place.Neighbourhood_id,
                        Cost = cost
                    };


                    await _carLogHistory.InsertAsync(carlog);  //插入进入场日志


                    await _carlogRealTime.DeleteAsync(carlogRealTime.Id);
                    place.PlaceSatus = 0;
                    _place.Update(place);
                }



            }
            else    //临时车
            {
                var outTiem = DateTimeToStamp(dt);


                var carlogRealTime = await _carlogRealTime.FirstOrDefaultAsync(c => c.CarNum == car.CarNum && c.ParkingId == device.ParkingId);

                var inTime = DateTimeToStamp(carlogRealTime.LogTime);
              
                var staytime = (outTiem - inTime) / 60;

                var realTime = staytime - billingScheme.FreeTime < 0 ? 0: staytime - billingScheme.FreeTime;  //如果实际停留时间 小于免费时间  时间等于 0 .否则为实际停留时间与免费时间的差值

                var cost = billingScheme.CappedPrice == 0 ? (realTime / billingScheme.IntervalTime) * billingScheme.Univalent : billingScheme.CappedPrice; //如果设置了封顶价格,价格为封顶价格,否则为实际价格


                carType = 3;
                var carlog = new CarLogHistory()
                {
                    LogType = vdc_type == "in" ? 1 : 2,
                    ParkingId = device.ParkingId,
                    CamId = cam_id,
                    GuardId = device.GuardId,
                    Ipaddr = cam_ip,
                    CarType = car.CarType == 0 ? 2 : 1,
                    LogTime = dt,
                    TenantId = device.TenantId,
                    Neighbourhood_id = device.Neighbourhood_id,
                    Cost = cost,
                    CarNum=car.CarNum,

                 
                };


                await _carLogHistory.InsertAsync(carlog);  //插入进入场日志
                

                await _carlogRealTime.DeleteAsync(carlogRealTime.Id);
                //place.PlaceSatus = 0;
                //_place.Update(place);
            }
            

            var json = ReturnJson(car);
            return json;
        }
        // DateTime时间格式转换为Unix时间戳格式
        private int DateTimeToStamp(System.DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return (int)(time - startTime).TotalSeconds;
        }
        private object ReturnJson(CarInfo car)
        {
            var carNum = car.CarNum;
            var type =  car.CarType==0?"临时车":"月租车";
            var testhexString = GetHexInfo(type,2);
            var carNumhexString = GetHexInfo(carNum,1);

            var ttt = carNum + type + "欢迎光临";
            var yyhexString = GetHexInfo(ttt, 3);



            var gpio_data = new List<Gpio_data>();


            var gpid = new Gpio_data()
            {
                ionum = "io1",
                action = "on"
            };

            gpio_data.Add(gpid);

            var rs485_data = new List<Rs485_data>();
            var data1 = new Rs485_data()
            {
                encodetype = "hex2string",
               data = carNumhexString

            };
            var data2 = new Rs485_data()
            {
                encodetype = "hex2string",
                data = testhexString
            };

            var data3 = new Rs485_data()
            {
                encodetype = "hex2string",
                data = yyhexString
            };
            rs485_data.Add(data1);
            rs485_data.Add(data2);
            rs485_data.Add(data3);
            //var triger_data = new Triger_data()
            //{
            //    action = "on"
            //};



            var returnData = new ReturnData()
            {
                error_num = 0,
                error_str = "",
                gpio_data = gpio_data,
                rs485_data = rs485_data,

            };


            var josn = Newtonsoft.Json.JsonConvert.SerializeObject(returnData);


            var t = JsonConvert.DeserializeObject(josn);

            var ccc = josn.Length.ToString();
            httpContext.HttpContext.Response.Headers.Add("Content-Length", ccc);
            return t;
        }



        /// <summary>
        /// 判断数据中crc是否正确
        /// </summary>
        /// <param name="datas">传入的数据后两位是crc</param>
        /// <returns></returns>
        public static bool IsCrcOK(byte[] datas)
        {
            int length = datas.Length - 2;

            byte[] bytes = new byte[length];
            Array.Copy(datas, 0, bytes, 0, length);
            byte[] getCrc = GetModbusCrc16(bytes);

            if (getCrc[0] == datas[length] && getCrc[1] == datas[length + 1])
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 传入数据添加两位crc
        /// </summary>
        /// <param name="datas"></param>
        /// <returns></returns>
        /// 
        [HttpPost]
        [Route("test111")]
        public static byte[] GetCRCDatas(byte[] datas)
        {
            int length = datas.Length;
            byte[] crc16 = GetModbusCrc16(datas);
            byte[] crcDatas = new byte[length + 2];
            Array.Copy(datas, crcDatas, length);
            Array.Copy(crc16, 0, crcDatas, length, 2);
            return crcDatas;
        }
        private static byte[] GetModbusCrc16(byte[] bytes)
        {
            byte crcRegister_H = 0xFF, crcRegister_L = 0xFF;// 预置一个值为 0xFFFF 的 16 位寄存器

            byte polynomialCode_H = 0xA0, polynomialCode_L = 0x01;// 多项式码 0xA001

            for (int i = 0; i < bytes.Length; i++)
            {
                crcRegister_L = (byte)(crcRegister_L ^ bytes[i]);

                for (int j = 0; j < 8; j++)
                {
                    byte tempCRC_H = crcRegister_H;
                    byte tempCRC_L = crcRegister_L;

                    crcRegister_H = (byte)(crcRegister_H >> 1);
                    crcRegister_L = (byte)(crcRegister_L >> 1);
                    // 高位右移前最后 1 位应该是低位右移后的第 1 位：如果高位最后一位为 1 则低位右移后前面补 1
                    if ((tempCRC_H & 0x01) == 0x01)
                    {
                        crcRegister_L = (byte)(crcRegister_L | 0x80);
                    }

                    if ((tempCRC_L & 0x01) == 0x01)
                    {
                        crcRegister_H = (byte)(crcRegister_H ^ polynomialCode_H);
                        crcRegister_L = (byte)(crcRegister_L ^ polynomialCode_L);
                    }
                }
            }

            return new byte[] { crcRegister_L, crcRegister_H };
        }












        public byte[] DelString(string str)
        {
            List<byte> frameBytes = new List<byte>();
            byte[] restr = new byte[str.Length/2];
            if (!string.IsNullOrEmpty(str))
            {
                ArrayList array = GetSeparateSubString(str, 2);
                
                foreach (string arr in array)
                {

                   // frameBytes.Add(arr);

                }

            }

            return restr;
        }


        private ArrayList GetSeparateSubString(string txtString, int charNumber) //charNumber为要截取的每段的长度
        {
            ArrayList arrlist = new ArrayList();
            string tempStr = txtString;
            for (int i = 0; i < tempStr.Length; i += charNumber)//首先判断字符串的长度，循环截取，进去循环后首先判断字符串是否大于每段的长度
            {
                if ((tempStr.Length - i) > charNumber)//如果是，就截取
                {
                    arrlist.Add(tempStr.Substring(i, charNumber));
                }
                else
                {
                    arrlist.Add(tempStr.Substring(i));//如果不是，就截取最后剩下的那部分
                }
            }
            return arrlist;
        }




        /// <summary>
        /// 获取hex2string
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static string GethexString(string str)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            var encoding = Encoding.GetEncoding("GB2312");
            byte[] bytes = encoding.GetBytes(str);
          //  byte[] bytes = Encoding.GetEncoding("GBK").GetBytes(str);
            var hexString = BitConverter.ToString(bytes);
            hexString = hexString.Replace("-", "");
            return hexString;
        }
    }
 




    public class ReturnData
    {
        public int error_num { set; get; }
        public string error_str { set; get; }
        public List<Gpio_data> gpio_data { set; get; }

        public List<Rs485_data> rs485_data { set; get; }
        //public Triger_data triger_data { set; get; }
    }

    public class Gpio_data
    {
        public string ionum { get; set; }
        public string action { get; set; }
    }

    public class Rs485_data
    {
        public string encodetype { get; set; }
        public string data { set; get; }
    }

    public class Triger_data
    {
        public string action { set; get; }
    }







}

